#include <iostream>
#include <fstream>
#include <vector>
#include <ctime>
#include <future>
#include <algorithm>
#include <thread>

using namespace std;


// Interesting testing results for VC11 Beta:
//
// 7 Mb file:
//
// Debug
// Simple reverse: 0.468
// Async reverse : 0.275
//
// Release
// Simple reverse: 0.006
// Async reverse : 0.014
//
//
// 98 Mb file:
//
// Debug
// Simple reverse: 5.982
// Async reverse : 3.091
//
// Release
// Simple reverse: 0.063
// Async reverse : 0.079
//
//
// 782 Mb file
//
// Release
// Simple reverse: 0.567
// Async reverse : 0.689
//
// In release simple version is always faster, so compiler is smarter than programmer =)

// Testing for mingw:
//
//
// 782 Mb file
//
// Release
// Simple reverse: 0.583
// Async reverse : 0.566
//
// So gcc is better in async operation even on windows

int main ()
{
	ifstream f("test.bin", ios::in | ios::binary | ios::ate);

	if (!f.is_open())
	{
		return -1;
	}

	size_t size = f.tellg();

	vector<char> data(size);
	f.seekg(0, ios::beg);
	f.read(&data[0], size);
	f.close();

	auto simple_reverse = [&data]() -> double
	{
		auto time_begin = clock();

		reverse(data.begin(), data.end());

		auto time_end = clock();
		return (double)(time_end - time_begin) / CLOCKS_PER_SEC;
	}();

	auto async_reverse = [&data]() -> double
	{
		auto time_begin = clock();

		unsigned int n_threads = thread::hardware_concurrency();
		vector<future<void>> holders(n_threads);

		for (unsigned int i = 0; i < n_threads; ++i)
		{
			size_t num = data.size() / 2 / n_threads;
			size_t pos = num * i;
			char *begin = &data[0] + pos;
			char *end = &data[0] + data.size() - 1 - pos;

			holders[i] = async(launch::async, [](char *b, char *e, size_t num)
				{
					while(b < e && num)
					{
						swap(*b, *e);
						++b;
						--e;
						--num;
					}
				}
				, begin
				, end
				, num
				);
		}

		for (auto &op : holders)
		{
			op.wait();
		}

		auto time_end = clock();
		return (double)(time_end - time_begin) / CLOCKS_PER_SEC;
	}();

	cout << "Simple reverse: " << simple_reverse << endl;
	cout << "Async reverse : " << async_reverse << endl;

	cin.get();

	return 0;
}

